package com.lhj.security.config.security.service;

import cn.hutool.jwt.*;
import com.google.common.cache.Cache;
import com.lhj.security.config.security.UserAuthDetail;
import com.lhj.security.constants.Constants;
import com.lhj.security.utils.IdUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description
 * @Author lhj
 * @Date 2024/12/27 14:21
 */
@Slf4j
@Service
public class TokenService {

    // 令牌自定义标识
    @Value("${token.header}")
    private String header;

    // 令牌秘钥
    @Value("${token.secret}")
    private String secret;

    // 令牌有效期（默认30分钟）
    @Value("${token.expireTime}")
    private int expireTime;

    @Resource
    private Cache<String, UserAuthDetail> userAuthDetailCache;

    protected static final long MILLIS_SECOND = 1000;

    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;

    /**
     * 创建令牌
     *
     * @param userAuthDetail 用户信息
     * @return 令牌
     */
    public String createToken(UserAuthDetail userAuthDetail) {
        String token = IdUtils.fastUUID();
        userAuthDetail.setToken(token);
        refreshToken(userAuthDetail);

        Map<String, Object> claims = new HashMap<>();
        claims.put(Constants.LOGIN_USER_KEY, token);
        return createToken(claims);
    }

    private String createToken(Map<String, Object> claims) {
        return JWTUtil.createToken(claims, secret.getBytes(StandardCharsets.UTF_8));
    }

    private void refreshToken(UserAuthDetail userAuthDetail) {
        userAuthDetail.setLoginTime(System.currentTimeMillis());
        userAuthDetail.setExpireTime(userAuthDetail.getLoginTime() + expireTime * MILLIS_MINUTE);
        //根据uuid缓存用户信息
        userAuthDetailCache.put(getTokenKey(userAuthDetail.getToken()), userAuthDetail);
    }

    private String getTokenKey(String token) {
        return Constants.LOGIN_USER_KEY + token;
    }


    public UserAuthDetail getLoginUser(HttpServletRequest request) {
        String token = getToken(request);
        if (StringUtils.hasText(token)) {
            String uuid = parseToken(token);
            String tokenKey = getTokenKey(uuid);
            return userAuthDetailCache.getIfPresent(tokenKey);
        }
        return null;
    }

    private String parseToken(String token) {
        JWT jwt = JWTUtil.parseToken(token);
        jwt.getHeader(JWTHeader.TYPE);
        return jwt.getPayload(Constants.LOGIN_USER_KEY).toString();
    }

    private String getToken(HttpServletRequest request) {
        String authorities = request.getHeader(Constants.AUTHORIZATION);
        if (StringUtils.hasText(authorities)) {
            if (StringUtils.startsWithIgnoreCase(authorities, Constants.TOKEN_PREFIX)) {
                return authorities.substring(Constants.TOKEN_PREFIX.length());
            }
            return authorities;
        }
        return null;
    }

    public void verifyToken(UserAuthDetail userAuthDetail) {
        long expire = userAuthDetail.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (expire - currentTime <= MILLIS_MINUTE_TEN) {
            refreshToken(userAuthDetail);
        }
    }
}
